package features.advance.jdk.agent;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import sun.jvmstat.monitor.*;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;

/**
 * @author LIN
 * @date 2022-05-06 19:54
 */
public class AttachSelf {

    public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
        String value = System.getProperty("jdk.attach.allowAttachSelf");
        boolean canAttachSelf = (value != null) && !value.equals("false");
        try {
            MonitoredHost localhost = MonitoredHost.getMonitoredHost("localhost");
            Set<Integer> set = new HashSet<>(localhost.activeVms());
            for (Integer processId : set) {
                MonitoredVm vm = localhost.getMonitoredVm(new VmIdentifier("//" + processId));
                String mainClass = MonitoredVmUtil.mainClass(vm, true);
                System.out.println(processId+"--------->"+mainClass);
            }

        } catch (MonitorException | URISyntaxException e) {
            e.printStackTrace();
        }
        RuntimeMXBean mxBean = ManagementFactory.getRuntimeMXBean();
        String name = mxBean.getName();
        String vmid = name.substring(0,name.indexOf("@"));
        VirtualMachine vm = null;
        try{
            vmid = "3884";
            vm = VirtualMachine.attach(vmid);
            /*
            在程序运行后加载，我们不可能在主程序中编写加载的代码，
            只能另写程序，那么另写程序如何与主程序进行通信？
            这里用到的机制就是attach机制，它可以将JVM A连接至JVM B，
            并发送指令给JVM B执行，JDK自带常用工具如jstack，jps等就是使用该机制来实现的。
             */
            vm.loadAgent("D:\\files\\zkr_micro_daily\\Core-Java\\out\\artifacts\\agentmain\\agentmain.jar","122222222222222222222222");
            if(!canAttachSelf){
                throw new RuntimeException("Attached to self not expected");
            }
        }catch(Exception e){
            if(canAttachSelf){
                throw e;
            }
        }finally {
            if(vm != null){
                vm.detach();
            }
        }
    }
    /*
    Java Agent十分强大，它能做到的不仅仅是打印几个监控数值而已，
    还包括使用Transformer（推荐观看https://www.jianshu.com/p/b72f66da679f）等高级功能进行类替换，方法修改等，
    要使用Instrumentation的相关API则需要对字节码等技术有较深的认识。

     */



}
